/**
 * 
 */
package com.hexacta.hrs.interfaces.holidays;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.junit.Test;

import com.hexacta.hrs.holidays.service.HolidaysService;
import com.hexacta.hrs.holidays.service.HolidaysServiceImpl;

/**
 * Tests de interfaz del web service de feriados. Testea el correcto
 * funcionamiento del web-service segun la especificacion de la interfaz y lo
 * que espera la aplicacion. Para que estos tests pasen es necesario que el web
 * service real este disponible.
 * 
 * @see http://www.mininterior.gov.ar/servicios/wsferiados.asp
 * 
 * @author sramusio
 */
public class HolidaysServiceTestI {

    /**
     * Testea que el web service devuelva una lista que incluya el 25-May-2008
     * cuando se consulta por el rango 25-Mar-2008 hasta 25-Dic-2008.
     */
    @Test(timeout = 10000)
    public void testHolidaysBetween() {
        HolidaysService holidaysService = new HolidaysServiceImpl();
        Calendar c1 = new GregorianCalendar(2008, Calendar.MARCH, 25);
        Calendar c2 = new GregorianCalendar(2008, Calendar.DECEMBER, 25);
        List<Date> holidays = holidaysService.holidaysBetween(c1.getTime(), c2.getTime());
        assertContainsDate(new GregorianCalendar(2008, Calendar.MAY, 25).getTime(), holidays);
    }

    /**
     * Testea que el webservice devuelva el 1-Nov-2008 como no feriado.
     */
    @Test(timeout = 10000)
    public void testAnyDateNotHolidayIsAHoliday() {
        HolidaysService holidaysService = new HolidaysServiceImpl();
        Calendar c1 = new GregorianCalendar(2008, Calendar.NOVEMBER, 1);
        assertFalse(holidaysService.isAHoliday(c1.getTime()));
    }

    /**
     * Testea que el webservice devuelva el 25-May-2008 como feriado.
     */
    @Test(timeout = 10000)
    public void testAHolidayIsAHoliday() {
        HolidaysService holidaysService = new HolidaysServiceImpl();
        Calendar c1 = new GregorianCalendar(2008, Calendar.MAY, 25);
        assertTrue(holidaysService.isAHoliday(c1.getTime()));
    }

    public static void assertContainsDate(final Date expectedDate, Collection<Date> actualDates) {
        assertNotNull(expectedDate);
        assertNotNull(actualDates);
        assertTrue(actualDates.toString(), CollectionUtils.exists(actualDates, new Predicate() {

            public boolean evaluate(Object object) {
                Date date = (Date) object;
                return HolidaysServiceTestI.equalsWithoutTime(date, expectedDate);
            }
        }));
    }

    // ---------------------------------------------------------------------
    // esto es feo. cosas copiadas del DateUtil para no tener dependencias
    // circulares entre proyectos

    /**
     * Determina si dos fechas son iguales sin tener en cuenta la fecha.
     * 
     * @param aDate
     *            una fecha
     * @param anotherDate
     *            otra fecha
     * @return true cuando las dos fechas son iguales sin tener en cuenta la
     *         fecha.
     */
    public static boolean equalsWithoutTime(Date aDate, Date anotherDate) {
        return equals(roundToDay(aDate), roundToDay(anotherDate));
    }

    /**
     * @param d1
     * @param d2
     * @return Indica si las dos fechas son iguales
     */
    public static boolean equals(Date d1, Date d2) {
        return (d1 == d2) || (d1 != null && d2 != null && d1.getTime() == d2.getTime());
    }

    /**
     * Redondea la fecha para no tener en cuenta la hora.
     * 
     * @param date
     * @return una fecha con hora 00.00.00.
     */
    public static Date roundToDay(Date date) {
        // Round down to nearest increment
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.MILLISECOND, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.HOUR, 0);
        cal.set(Calendar.AM_PM, Calendar.AM);

        Date segmentStartDate = cal.getTime();

        return (segmentStartDate);
    };
}
